﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using BlobNet.Base.Interfaces;

namespace BlobNet.Base.Common
{
    internal class ObjectBuilder
    {
        #region singleton
        private static ObjectBuilder _default = new ObjectBuilder();
        private ObjectBuilder() { }

        public static ObjectBuilder Default
        {
            get { return _default; }
        } 
        #endregion

        public TType GetNewInstance<TType>(params object[] initializationParams) where TType : ILateInitializable
        {
            var type = typeof (TType);
            var result = (TType)BuildInstance(type,initializationParams);
            return result;
        }

        private static object BuildInstance(Type type,params object[] initializationParams) 
        {
            ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, System.Type.EmptyTypes, null);

            if (constructorInfo == null)
                throw new InvalidOperationException(string.Format(
                    "The type {0} must have an empty constructor. It can be private",
                    type.FullName));

            ILateInitializable result = (ILateInitializable)constructorInfo.Invoke(Type.EmptyTypes);
            //TODO: READER WRITER PROBLEM. HAVE PRELOADED SEVERAL OBJECTS WHEN REACHING THIS POINT, PICK ONE

            result.InitializeObjectStatus(initializationParams);
            return result;
        }

        public object GetNewInstance(string fullTypeName, params object [] initializationParams)
        {
            //TODO: OPTIMIZE
            var types = (from a in AppDomain.CurrentDomain.GetAssemblies()
                         from t in a.GetTypes()
                         select t).ToList();
            Type type=types.SingleOrDefault(x => x.FullName == fullTypeName);
            if(type==null)
                type = Type.GetType(fullTypeName, true);
            return BuildInstance(type, initializationParams);
        }

    }
}
